package com.lagou.edu.factory;


import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Component;
import com.lagou.edu.annotation.Controller;
import com.lagou.edu.annotation.Repository;
import com.lagou.edu.annotation.Serivce;
import com.lagou.edu.annotation.Transactional;
import com.lagou.edu.pojo.RootBeanDefinition;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class AbstructBeanFactory {

    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */


    // 封装所有的bean容器，一级缓存
    public final static ConcurrentHashMap<String, Object> beans = new ConcurrentHashMap<>();

    // 封装所有的bean容器，二级缓存
    public final static ConcurrentHashMap<String, Object> earlyBeans = new ConcurrentHashMap<>();

    // 当前正在创建的bean的名称
    public final static Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        return beans.get(id);
    }



    /**
     * 扫描包下的所有类，并创建bean
     * @param filePath 文件路径
     * @param packageName 包路径
     * @param isRecursion 是否遍历子包
     * @return 类的完整名称
     */
    public static void createBean(String filePath, String packageName, boolean isRecursion) throws Exception {
        File file = new File(filePath);
        File[] files = file.listFiles();
        // 遍历目录下的所有人间和子目录
        for (File childFile : files) {
            if (childFile.isDirectory()) {
                if (isRecursion) {
                    createBean(childFile.getPath(), packageName+"."+childFile.getName(), isRecursion);
                }
            } else {
                String fileName = childFile.getName();
                if (fileName.endsWith(".class") && !fileName.contains("$")) {
                    // 获取初加工的RootBeanDefinition
                    String classpath = packageName + "."+ fileName.replace(".class", "");
                    RootBeanDefinition beanDefinition = getBeanDefinition(classpath);
                    if (beanDefinition != null) {
                        doCreateBean(beanDefinition);
                    }
                }
            }
        }
    }

    /**
     * 获取初加工的RootBeanDefinition
     * @param classPath
     * @return
     * @throws ClassNotFoundException
     */
    public static RootBeanDefinition getBeanDefinition(String classPath) throws ClassNotFoundException {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setClassPath(classPath);
        String beanId = null;
        // 通过反射技术实例化对象
        Class<?> clazz = Class.forName(classPath);
        rootBeanDefinition.setBeanClass(clazz);
        // 如果没有spring的注解，则不实例化
        Serivce serivce;
        Controller controller ;
        Repository repository;
        Component component;

        if ((serivce = clazz.getAnnotation(Serivce.class)) != null) {
            if (StringUtils.isNotBlank(serivce.id())) {
                beanId = serivce.id();
            }
        } else if ((controller = clazz.getAnnotation(Controller.class)) != null) {
            if (StringUtils.isNotBlank(controller.id())) {
                beanId = controller.id();
            }
        } else if ((repository = clazz.getAnnotation(Repository.class)) != null) {
            if (StringUtils.isNotBlank(repository.id())) {
                beanId = repository.id();
            }
        } else if ((component = clazz.getAnnotation(Component.class)) != null) {
            if (StringUtils.isNotBlank(component.id())) {
                beanId = repository.id();
            }
        } else {
            return null;
        }
        if (StringUtils.isBlank(beanId)) {
            beanId = toLowerCaseFirstOne(clazz.getSimpleName());
        }
        rootBeanDefinition.setBeanId(beanId);
        return rootBeanDefinition;
    }


    /**
     * 实例化bean
     * @param beanDefinition
     * @return
     * @throws Exception
     */
    public static Object doCreateBean(RootBeanDefinition beanDefinition) throws Exception {
        //存入当前正在创建bean的名称
        singletonsCurrentlyInCreation.add(beanDefinition.getBeanId());

        // 从一级缓存中获取
        Object bean = beans.get(beanDefinition.getBeanId());
        if (bean != null) {
            return bean;
        }

        // 都拿不到值，开始反射创建
        Object object = beanDefinition.getBeanClass().newInstance();
        Field[] fields = beanDefinition.getBeanClass().getDeclaredFields();



        // 遍历所有成员字段，如果有autowary则自动注入
        for (Field field : fields) {
            Autowired annotation = field.getAnnotation(Autowired.class);
            Object fieldObject = null;
            if (annotation != null) {
                Class<?> fieldClazz = field.getType();
                RootBeanDefinition fieldBeanDefinition = getBeanDefinition(fieldClazz.getCanonicalName());

                // 解决循环依赖
                // 如果要创建的成员变量类在创建池里已经存在，说明他之前的创建过程没结束，存在循环依赖
                if (singletonsCurrentlyInCreation.contains(beanDefinition.getBeanId())) {
                    // 尝试从一级缓存拿
                    fieldObject = beans.get(fieldBeanDefinition.getBeanId());
                    if (bean == null) {
                        // 尝试从二级缓存拿
                        fieldObject = earlyBeans.get(fieldBeanDefinition.getBeanId());
                        if (bean != null) {
                            // 如果从二级缓存拿到，说明创建顺序已经是ABA->B，拿到了提前暴露的B，我们把他从二级缓存删掉
                            earlyBeans.remove(fieldBeanDefinition.getBeanId());
                        } else {
                            // 如果二级缓存没拿到，说明创建顺序在AB->A，则将主类B放入二级缓存提前暴露，好让ABA->B的时候能拿到
                            earlyBeans.put(beanDefinition.getBeanId(), object);
                        }
                    }

                }
                if (fieldObject == null) {
                    fieldObject = doCreateBean(fieldBeanDefinition);
                }

                if (fieldObject != null) {
                    // 默认使用属性名称，查找bean容器对象 1参数 当前对象 2参数给属性赋值
                    field.setAccessible(true); // 允许访问私有属性
                    field.set(object, fieldObject);
                }
            }
        }

        // 开启事务代理
        Annotation transactional = beanDefinition.getBeanClass().getAnnotation(Transactional.class);
        if (transactional != null) {
            ProxyFactory proxyFactory = (ProxyFactory) beans.get(toLowerCaseFirstOne(ProxyFactory.class.getSimpleName()));
            boolean isInterFace = beanDefinition.getBeanClass().isInterface();
            if (isInterFace) {
                object =  proxyFactory.getJdkProxy(object);
            } else {
                object =  proxyFactory.getCglibProxy(object);
            }

        }
        // 加入一级缓存
        beans.put(beanDefinition.getBeanId(), object);

        // 创建完毕，从当前创建列表删除
        singletonsCurrentlyInCreation.remove(beanDefinition.getBeanId());
        return object;
    }

    /**
     *  首字母转小写
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    }


}
